﻿/*
 * File: MapWindow.cs
 * Developer : Brent Larsen (brentoboy@gmail.com)
 * Date: 2011-AUG-9
 * Copyright (c) 2011 Brent Larsen.
 * Distributed under the terms of the GPL v3
 *  
 * This file is part of GenX-RPG
 * http://code.google.com/p/genx-rpg/ 
 * 
 * GenX-RPG is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GenX-RPG is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with GenX-RPG.  If not, see <http://www.gnu.org/licenses/>.
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;

namespace Rpg.Game
{
    public partial class MapWindow : OwnerDraw
    {
        private const int GRID_SIZE = 25;
        private const int MID_X = 12;
        private const int MID_Y = 12;

        private Map _map;

        private Dictionary<string, Bitmap> _tileBitmaps = new Dictionary<string, Bitmap>();

        private Image _sprites = Rpg.Properties.Resources.SpritesGif;
        private Rectangle _mapRect;
        private Bitmap _mapBmp;
        private Bitmap _canvas;

        private Point _origin = new Point(0,0);

        public MapWindow()
        {
            InitializeComponent();
        }

        // only needs to be done once, when loading a new map
        public void _drawMap()
        {
            var mainWindow = (this.Parent as GameWindow);
            _map = mainWindow.CurrentMap;
            //_origin.X = mainWindow.CurrentX;
            //_origin.Y = mainWindow.CurrentY;

            var mapWidthInCells = _map.Width;
            var mapHeightInCells = _map.Height;
            var mapWidthInPixels = mapWidthInCells * Tile.SQUARE_SIZE;
            var mapHeightInPixels = mapHeightInCells * Tile.SQUARE_SIZE;

            using (var g = this.CreateGraphics())
            {
                if (_canvas == null)
                    _canvas = new Bitmap(this.Width, this.Height, g);

                _mapBmp = new Bitmap(mapWidthInPixels, mapHeightInPixels, g);
                _mapRect = new Rectangle(0, 0, mapWidthInPixels, mapHeightInPixels);
            }

            using (var g = Graphics.FromImage(_mapBmp))
            {
                g.FillRectangle(Brushes.Black, 0, 0, mapWidthInPixels, mapWidthInCells);

                for (int x = 0; x < mapWidthInCells; x++)
                {
                    for (int y = 0; y < mapHeightInCells; y++)
                    {
                        var cell = _map.Cells[x, y];
                        var tile = _map.Tiles[cell.TileId];
                        var tileBitmap = _tileBitmaps[tile.BmpName];
                        g.DrawImage(tileBitmap, new Rectangle(x * Tile.SQUARE_SIZE, y * Tile.SQUARE_SIZE, Tile.SQUARE_SIZE, Tile.SQUARE_SIZE), new Rectangle(tile.BmpX, tile.BmpY, Tile.SQUARE_SIZE, Tile.SQUARE_SIZE), GraphicsUnit.Pixel);
                    }
                }

                g.Dispose();
            }
        }

        public void _drawCanvas()
        {
            // make sure you have the right map in the pre-render bitmap
            if (_map != (this.Parent as GameWindow).CurrentMap)
            {
                _drawMap();
            }

            // render all of the additional stuff on top of it
            using (var g = Graphics.FromImage(_canvas))
            {
                if (g != null && _mapBmp != null)
                {
                    // black out the drawing area
                    g.Clear(Color.Black);

                    // paint the map
                    // assumes _mapBmp is updated to current "known" map, and _mapRect is initialized to the size of the current map
                    // assumes origin is correct
                    g.DrawImage(_mapBmp, (MID_X - _origin.X) * Tile.SQUARE_SIZE, (MID_Y - _origin.Y) * Tile.SQUARE_SIZE, _mapRect, GraphicsUnit.Pixel);

                    // paint the fog
                    // fog is painted on squairs in the view area
                    //  where the map is known
                    //  that are not currently visible

                    // assumes _map.Cells.IsCurrentlyVisible is correct
                    // first find the xy range that is overlap of the map and the view pane
                    int minX = Math.Max(-MID_X, -_origin.X);
                    int minY = Math.Max(-MID_Y, -_origin.Y);

                    int maxX = Math.Min(MID_X, ((_map.Width - 1) - _origin.X));
                    int maxY = Math.Min(MID_Y, ((_map.Height - 1) - _origin.Y));

                    // loop the range
                    for (int x = minX; x <= maxX; x++)
                    {
                        for (int y = minY; y <= maxY; y++)
                        {
                            var cell = _map.Cells[x + _origin.X, y + _origin.Y]; //todo, adjust for origin

                            //// look for Known cells that are not visible
                            //if (cell.State > 0 && !cell.IsCurrentlyVisible == true)
                            //{
                            //    //g.DrawImage(_sprites, (x + 14) * SQUARE_SIZE, (y + 14) * SQUARE_SIZE, new Rectangle(0, SQUARE_SIZE, SQUARE_SIZE, SQUARE_SIZE), GraphicsUnit.Pixel);
                            //}
                        }
                    }

                    //// add pieces that are on visible cells
                    //{
                    //    int x = 1; int y = -2;
                    //    g.DrawImage(_sprites, (x + 14) * SQUARE_SIZE, (y + 14) * SQUARE_SIZE, new Rectangle(0, SQUARE_SIZE * 4, SQUARE_SIZE, SQUARE_SIZE), GraphicsUnit.Pixel);
                    //}

                    // add characters...
                    {
                        int x = Program.MainWindow.CurrentX - _origin.X;
                        int y = Program.MainWindow.CurrentY - _origin.Y;
                        g.DrawImage(_sprites, (x + MID_X) * Tile.SQUARE_SIZE, (y + MID_Y) * Tile.SQUARE_SIZE, new Rectangle(Tile.SQUARE_SIZE * 0, Tile.SQUARE_SIZE * 2, Tile.SQUARE_SIZE, Tile.SQUARE_SIZE), GraphicsUnit.Pixel);
                    }
                }
            }
        }

        public void SetOrigin(int x, int y)
        {
            //if (_map == null)
            //{
            //    _origin.X = x;
            //    _origin.Y = y;
            //}
            //else
            //{
            if (Program.MainWindow.CurrentMap.Width <= MapWindow.GRID_SIZE)
                _origin.X = Program.MainWindow.CurrentMap.Width / 2;
            else if (x < MID_X)
                _origin.X = MID_X;
            else if (x > Program.MainWindow.CurrentMap.Width - MID_X)
                _origin.X = Program.MainWindow.CurrentMap.Width - MID_X;
            else
                _origin.X = x;

            if (Program.MainWindow.CurrentMap.Height <= MapWindow.GRID_SIZE)
                _origin.Y = Program.MainWindow.CurrentMap.Height / 2;
            else if (y < MID_Y)
                _origin.Y = MID_Y;
            else if (y > Program.MainWindow.CurrentMap.Height - MID_Y)
                _origin.Y = Program.MainWindow.CurrentMap.Height - MID_Y;
            else
                _origin.Y = y;

            this.Refresh();
        }

        public override void Refresh()
        {
            if (this.InvokeRequired)
            {
                BeginInvoke((Action)(() => this.Refresh()));
            }
            else
            {
                _drawCanvas();
                base.Refresh();
            }
        }

        private void MapWindow_Paint(object sender, PaintEventArgs e)
        {
            if (_canvas != null)
                e.Graphics.DrawImage(_canvas, new Point(0, 0));
        }
    }
}
